﻿using System;
using System.IO;
using System.Net;
using Newtonsoft.Json;
using System.Threading;
using System.Configuration;
using ACSTools.DataContracts;
using System.Collections.Generic;

namespace ACSTools.RestConsumer
{
    public class PrimeHomeWS
    {
        public PrimeHomeWS()
        {
            wsURL = ConfigurationManager.AppSettings["wsURL"];
            wsUser = ConfigurationManager.AppSettings["wsUser"];
            wsPassword = ConfigurationManager.AppSettings["wsPassword"];
        }
   
        #region Definitions

        private enum putMethod
        {
            POST,
            PUT
        }

        private static string wsURL;

        private static string wsUser;

        private static string wsPassword;

        #endregion

        #region Methods: Private
        
        private static string getJsonObject(string url)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.KeepAlive = false;
            request.Method = "GET";
            request.Credentials = new NetworkCredential(wsUser, wsPassword);
            request.ContentType = "application/json; charset=utf-8";
            try
            {
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                Stream dataStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(dataStream);
                string strStream = reader.ReadToEnd();

                dataStream.Close();

                return strStream;
            }
            catch (Exception) 
            {
                return string.Empty;
            }
        }

        private static bool putJsonObject(string url, string Object, putMethod method)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.KeepAlive = false;
            if (method == putMethod.POST) request.Method = "POST"; else request.Method = "PUT";
            request.Credentials = new NetworkCredential(wsUser, wsPassword);
            request.ContentType = "application/json; charset=utf-8";
            try 
            {
                Stream dataStream = request.GetRequestStream();
                StreamWriter writer = new StreamWriter(dataStream);
                writer.Write(Object);
                writer.Close();

                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                dataStream.Close();

                return true;
            }
            catch (Exception) 
            {
                return false;
            }
        }

        private static bool deleteJsonObject(string url)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.KeepAlive = false;
            request.Method = "DELETE";
            request.Credentials = new NetworkCredential(wsUser, wsPassword);
            request.ContentType = "application/json; charset=utf-8";
            try
            {
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                return true;
            }
            catch (Exception)
            {
                Thread.Sleep(6000);
                return false;
            }
        }

        private static string caqlQuery(string query, int page, int count)
        {
            if (page == 0) page = 1;

            string url = wsURL + "portal/query/execute?count=" + count.ToString() + "&first=" + page.ToString();

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.KeepAlive = false;
            request.Method = "POST";
            request.Credentials = new NetworkCredential(wsUser, wsPassword);
            request.ContentType = "application/json; charset=utf-8";

            Stream dataStream = request.GetRequestStream();
            StreamWriter writer = new StreamWriter(dataStream);
            writer.Write(query);
            writer.Close();

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            if (response.StatusCode != HttpStatusCode.OK)
                throw new Exception(String.Format("Server error (HTTP {0}: {1}).", response.StatusCode, response.StatusDescription));

            dataStream.Close();

            dataStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(dataStream);
            string result = reader.ReadToEnd();
            reader.Close();

            dataStream.Close();

            return result;
        }

        #endregion

        #region Methods: Public

        #region Device
        // Get device base
        public Device createDeviceFromTemplate()
        {
            string url = wsURL + "api/current/templates/device";
            return JsonConvert.DeserializeObject<Device>(getJsonObject(url));
        }
        // Put new device
        public bool putDevice(Device device)
        {
            string url = wsURL + "api/current/devices/";
            putMethod method = putMethod.POST;

            if (device.deviceId != null)
            {
                url = url + device.deviceId;
                method = putMethod.PUT;
            }

            string d = JsonConvert.SerializeObject(device, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });

            return putJsonObject(url, d, method);
        }
        // Put device actions
        public bool putDeviceActions(string deviceId, DeviceAction deviceActions)
        {
            if (deviceId != string.Empty && deviceActions != null)
            {
                string url = wsURL + "api/current/devices/";

                putMethod method = putMethod.PUT;

                url = url + deviceId + "/actions";

                string d = JsonConvert.SerializeObject(deviceActions, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore});

                return putJsonObject(url, d, method);
            }
            else return false;
        }
        // Get device actions
        public DeviceAction getDevicActions(string deviceId)
        {
            string url = wsURL + "api/current/devices/" + deviceId + "/actions";
            return JsonConvert.DeserializeObject<DeviceAction>(getJsonObject(url));
        }
        // Get device by Id
        public Device getDeviceById(string deviceId)
        {
            string url = wsURL + "api/current/devices/" + deviceId;
            return JsonConvert.DeserializeObject<Device>(getJsonObject(url));
        }
        // Get device by MAC
        public Device getDeviceByMAC(string deviceMAC)
        {
            string url = wsURL + "api/current/devices/sn:" + deviceMAC;
            return JsonConvert.DeserializeObject<Device>(getJsonObject(url));
        }
        // Get device by filter
        public Device[] getDeviceByFilter(string filter)
        {
            string url = wsURL + "api/current/devices?filter=" + filter + "?count=1000";
            return JsonConvert.DeserializeObject<Device[]>(getJsonObject(url));
        }
        // Delete device
        public bool deleteDevice(string deviceId)
        {
            string url = wsURL + "api/current/devices/" + deviceId;
            return deleteJsonObject(url);
        }

        #endregion

        #region Subscriber

        public Subscriber createSubscriberFromTemplate()
        {
            string url = wsURL + "api/current/templates/subscriber/";
            return JsonConvert.DeserializeObject<Subscriber>(getJsonObject(url));
        }

        public bool putSubscriber(Subscriber subscriber)
        {
            string url = wsURL + "api/current/subscribers/";
            putMethod method = putMethod.POST;

            if (subscriber.subscriberId != null)
            {
                url = url + subscriber.subscriberId;
                method = putMethod.PUT;
            }

            string s = JsonConvert.SerializeObject(subscriber, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });

            return putJsonObject(url, s, method);
        }

        public Subscriber getSubscriberById(string subscriberId)
        {
            string url = wsURL + "api/current/subscribers/" + subscriberId;
            return JsonConvert.DeserializeObject<Subscriber>(getJsonObject(url));
        }

        public Subscriber getSubscriberByCode(string subscriberCode)
        {
            string url = wsURL + "api/current/subscribers/code:" + subscriberCode;
            return JsonConvert.DeserializeObject<Subscriber>(getJsonObject(url));
        }

        public Subscriber[] getSubscriberByFilter(string filter)
        {
            string url = wsURL + "api/current/subscribers?filter=" + filter + "?count=1000";
            return JsonConvert.DeserializeObject<Subscriber[]>(getJsonObject(url));
        }

        public bool deleteSubscriber(string subscriberId)
        {
            string url = wsURL + "api/current/subscribers/" + subscriberId;
            return deleteJsonObject(url);
        }

        #endregion

        #region CALQ

        public calqResult[] calq(string query, int maxRecords)
        {
            int page = 1;
            int count = 0;
            int records = maxRecords;
            string result = "";
            string temp = "";

            while (records > 0 | maxRecords == 0)
            {
                count = (records > 100 | maxRecords == 0) ? 100 : records;
                temp = caqlQuery(query, page, count);

                if (temp == "[]") break;

                temp = temp.TrimStart('[');
                temp = temp.TrimEnd(']');

                result += (result == "") ? "[" + temp : "," + temp;

                records = (records - count);
                page = (page + 100);
            }
            if (result != "") result += "]";
            return JsonConvert.DeserializeObject<calqResult[]>(result);
        }

        #endregion

        #endregion

    }
}
